package com.calm.editor.point;  
  
import java.io.StringReader;
import java.lang.reflect.Method;

import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;

import org.springframework.context.ApplicationContext;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.calm.editor.servlet.Parameter;
import com.calm.editor.servlet.Result;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.google.gson.stream.JsonReader;
  
public class WebsocketEndPoint extends TextWebSocketHandler {
	@Resource
	private ApplicationContext context;
	@Resource
	private EntityManagerFactory emf;
	private Gson gson = new GsonBuilder().addSerializationExclusionStrategy(new ExclusionStrategy() {
		
		@Override
		public boolean shouldSkipField(FieldAttributes f) {
			Expose annotation = f.getAnnotation(Expose.class);
			if(annotation==null){
				return false;
			}
			return !annotation.serialize();
		}
		
		@Override
		public boolean shouldSkipClass(Class<?> clazz) {
			return false;
		}
	}).create();
    @Override  
    protected void handleTextMessage(WebSocketSession session,  
            TextMessage message) throws Exception {
    	boolean participate = false;
    	if (TransactionSynchronizationManager.hasResource(emf)) {
			// Do not modify the EntityManager: just set the participate flag.
			participate = true;
		}else{
			Object resource = TransactionSynchronizationManager.getResource(emf);
	    	if(resource==null){
	    		EntityManagerHolder emHolder = new EntityManagerHolder(emf.createEntityManager());
	    		TransactionSynchronizationManager.bindResource(emf, emHolder);
	    	}
		}
    	try{
    		JsonReader aa = new JsonReader(new StringReader(message.getPayload()));
    		aa.setLenient(true);
    		Parameter para = gson.fromJson(aa, Parameter.class);
    		Result<?> result=new Result<>();
    		try {
    			Object bean = context.getBean(para.getBean());
    			Class<?> clazz = bean.getClass();
    			Method[] methods = clazz.getMethods();
    			for(Method m:methods){
    				if(m.getName().equals(para.getMethod())){
    					Class<?>[] parameterTypes = m.getParameterTypes();
    					int length=parameterTypes.length;
    					Object[] args=new Object[length];
    					for(int i=0;i<length;i++){
    						Class<?> type = parameterTypes[i];
    						if(type.equals(Result.class)){
    							args[i]=result;
    						}else{
    							Object fromJson = gson.fromJson(para.getData(), parameterTypes[0]);
    							args[i]=fromJson;
    						}
    					}
    					m.invoke(bean, args);
    					break;
    				}
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    			result.setMessage(e.getMessage());
    			result.setStatus(Result.STATUS_ERROR);
    		}
    		String json = gson.toJson(result);
			session.sendMessage(new TextMessage(json));
    	}finally{
    		if (!participate) {
				EntityManagerHolder emHolder = (EntityManagerHolder)
						TransactionSynchronizationManager.unbindResource(emf);
//					logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewFilter");
				EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
			}
    	}
    	
    }  
}  